Fork me on GitHub

【cuckoo沙箱系列0】cuckoo沙箱总体框架介绍

因为毕设需要,准备搭建一个稍有规模的分布式cuckoo沙箱。目前进展:
在2个物理机上配置了cuckoo host,在1个虚拟机上搭建了distributed server。将这2个host挂载在了server端,向server端发送运行任务后,server端会安排2个host轮流完成运行任务。

cuckoo host

单个cuckoo沙箱节点是由以下部分组成的:

  • cuckoo主程序×1
  • virtualbox×1(里面安装了多个虚拟机系统,每个系统都配置好了agent)
  • mysql数据库×1(用于存放当前cuckoo节点的运行记录)
  • mongo数据库×1(用于存放当前cuckoo节点的运行报告,json格式)

单个cuckoo节点的功能:

  • cuckoo -d(开启后台分析进程)
  • cuckoo web(开启web端从而在网页上提交样本进行分析、查看报告)
  • cuckoo api(开启api接口提交样本,如果后面要搭建distributed cuckoo也需要开启它)

distributed cuckoo

分布式cuckoo的组成:

  • distributed server(运行着server的一个节点)
  • distributed worker(多个cuckoo节点)
  • 数据库×1(用于存放distributed server端下发任务的记录)

worker
组成分布式worker的cuckoo节点首先是一个独立可以运行沙箱任务的,已经配置好的节点。所以在将某个节点加入到分布式cuckoo之前,需要先测试一下它本身是否能顺利完成分析任务。

在此基础上,开启后台cuckoo(https://cuckoo.sh/docs/usage/start.html#cuckoo-in-the-background)
,开启api调用(cuckoo api)并注释掉其cuckoo.conf中的api_token = xxx(把这边注释掉就不需要api_token的验证了),并且额外运行:

supervisorctl start distributed

server
server节点的功能就是调度各个worker节点,本身不需要运行软件、生成报告。因此开启server的节点不要求运行cuckoo -d,只需要运行:

cuckoo distributed server

注册worker到server

curl http://server的ip:9003/api/node -F name=worker的名字 -F url=http://worker的ip:8090/

worker被server调用的方式就是通过api调用。当你向【server的ip:9003】下发任务时,server会寻找合适、空闲的worker,把任务下发到【worker的ip:8090】,下发任务到server时也可以直接指定让某个worker的某个虚拟机来运行本次的软件。

todo

以上都是基于cuckoo自带的distributed功能实现,总的来说能够完成分布式沙箱运行软件的目标。但是其本身有一些我认为待改进的地方:

  1. worker本地的原始文件会被自动删除
    将cuckoo host挂载到了distributed server后,当前cuckoo就成为了一个worker。server安排了某个软件运行task给worker执行结束后,worker会将运行报告以json格式存储到配置好的mongo数据库里。不会在本地存储pcap、截图等文件了(因为会在存储report到mongo之后立删除本地的这些文件,从而节省空间)。
    然而本地存储的文件其实是很大的,比如不通过server下发任务,而是通过cuckoo host本地开启的web提交任务,结束后在.cuckoo/storage/analyses这个路径下会存储完整的pcap、截图、内存等文件,一般都有90MB。但存储到mongo数据库中的json其实是缩水了很多的,而且api(存储在calls表)和截图等(存储在fs.chunks)和报告(存储在 analysis)是分开存储的。

  2. worker之间的id会冲突
    server下发任务之后会有一个distributed task id,worker收到server下发的程序后会产生自己的task id(这个id是每个worker节点自己从1开始累加标号的)。worker运行完毕后会把报告存到mongo数据库,对应的report有自己的mongoid。
    然而report只和task id关联了,没有和distributed task id关联。

  • 举一个report的例子(只截取了前面的一部分):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    {
    "_id": ObjectId("5e12a0fc6696137e8ab1f46c"),
    "info": {
    "added": ISODate("2020-01-06T10:51:07.000Z"),
    "started": ISODate("2020-01-06T10:51:08.000Z"),
    "duration": 93,
    "analysis_path": "/home/tangmingyu/.cuckoo/storage/analyses/2",
    "ended": ISODate("2020-01-06T10:52:41.000Z"),
    "owner": null,
    "score": 0,
    "id": 2,
    "category": "file",
    "git": {
    "head": "13cbe0d9e457be3673304533043e992ead1ea9b2",
    "fetch_head": "13cbe0d9e457be3673304533043e992ead1ea9b2"
    },
    "monitor": "2deb9ccd75d5a7a3fe05b2625b03a8639d6ee36b",
    "package": "exe",
    "route": "none",
    "custom": null,
    "machine": {
    "status": "stopped",
    "name": "cuckoo1",
    "label": "cuckoo1",
    "manager": "VirtualBox",
    "started_on": "2020-01-06 10:51:08",
    "shutdown_on": "2020-01-06 10:52:41"
    },
    "platform": "windows",
    "version": "2.0.7",
    "options": "procmemdump=yes,route=none"
    },

可以看出mongoid为5e12a0fc6696137e8ab1f46c,id为2.但这个id是task id,不是一个唯一对应值。比如有两个cuckoo节点,tmy和tmy2,它们各自运行任务时都会将task id从1开始标号,因此是有冲突的。

目前我的解决方法:
给不同的cuckoo节点安排不同的mongo数据库,比如给tmy这个节点安排的mongo数据库是cuckoo_db,给tmy安排的是cuckoo_db2,那么在每个db中id就可以唯一标志一个任务了。

-------------本文结束感谢您的阅读-------------